<?php

/**
 * 数据库单表CURD操作类
 * 注意：操作的表必须含有单一主键字段
 * @example
 *  $curd = SCS::curd('Admin'); // 实例化表模型
 *  $curd->create(array('name' => 'admin', 'addTime' => '{NOW()}')); // 创建记录
 *  echo $curd->name, $curd->addTime; // 读取属性
 *  $curd = SCS::curd('Admin')->read('name = "admin"'); // 字段name为admin的记录
 *  $curd = SCS::curd('Admin')->read(3); // 主键值为3的记录 
 *  $curd->name = 'keluo'; // 设置name字段值
 *  $curd->update(); // 更新全部字段
 *  $curd->update(array('name' => 'keluo')); // 更新特定字段
 *  $curd->delete(); // 删除记录
 *  $list = SCS::curd('Admin')->readAll('name LIKE "%a%"'); // 多条CURD实例
 *  $list = SCS::curd('Admin')->readAll(null, 'ORDER BY id DESC LIMIT 10'); // 其他条件
 * @author keluo<pycorvn@yeah.net>
 * @since 2015-01-24
 */
class SCCurd {
        
    private $_connect = null;
    private $_table = null;
    private $_fields = array();
    private $_pkName = null;
    private $_pkValue = null;
    private $_attributes;
    
    /**
     * 实例化单表原子操作模型
     * @param string $table 表名
     * @param string $connect 数据库连接标识
     * @throws Exception
     */
    public function __construct($table, $connect = null) {
        $this->_connect = $connect ? $connect : SCS::config()->connect;
        $this->_table = $table;
        $db = new SCDb($connect);
        $this->_pkName = $db->getTableStruct(SCS::config()->db[$this->_connect]['prefix'].$this->_table, 'pk');
        $this->_fields = $db->getTableStruct(SCS::config()->db[$this->_connect]['prefix'].$this->_table);
        
        if(is_null($this->_pkName)) throw new Exception('无法创建原子操作模型：表'.$this->_connect.'.'.$this->_table.'需要包含一个主键字段');
    }
    
    /**
     * 创建记录
     * @param array $data 数据，field=>value
     * @return SCCurd
     */
    public function create(array $data) {
        $this->_pkValue = SCS::db($this->_connect)->from($this->_table)->insert($data);
        $this->_attributes = SCS::db($this->_connect)->from($this->_table)
        ->where($this->_pkName.' = "'.$this->_pkValue.'"')->fetch();
        return $this;
    }
    
    /**
     * 更新记录
     * @param array $data 数据，field=>value
     */
    public function update(array $data) {
        foreach($data as $field=>$value) {
            if(in_array($field, $this->_fields)) {
                $this->_attributes->$field = $value;
            }
        }
        
        SCS::db($this->_connect)->from($this->_table)->where($this->_pkName.' = "'.$this->_pkValue.'"')->update($data);
        
        // 重新更新主键值(考虑到上一步更新操作可能会更新主键值)
        $this->_pkValue = $this->_attributes->{$this->_pkName};
    }
    
    /**
     * 读取记录
     * @param mixed $condition 为数值时表示主键值，为表达式则表示条件
     * @param boolean $returnOnlyAttributes 是否仅返回属性合集
     * @return object
     */
    public function read($condition, $extra = null, $returnOnlyAttributes = false) {
        if(is_numeric($condition)) {
            $record = SCS::db($this->_connect)->from($this->_table)->where($this->_pkName.' = "'.$condition.'"')->fetch();
        } else {
            $record = SCS::db($this->_connect)->find('SELECT * FROM '.
            SCS::config()->db[$this->_connect]['prefix'].$this->_table.
            ($condition ? ' WHERE '.$condition : '').($extra ? (' '.$extra) : ''));
        }
        
        if($record) {
            $this->_attributes = $record;
            $this->_pkValue = $this->_attributes->{$this->_pkName};
            return $returnOnlyAttributes ? $this->attributes() : $this;
        }
        return null;
    }
    
    /**
     * 删除记录
     */
    public function delete() {
        return SCS::db($this->_connect)->from($this->_table)->where($this->_pkName.' = "'.$this->_pkValue.'"')->delete();
    }
    
    /**
     * 返回多条记录 
     * @param string $condition
     * @param string $extra
     * @param boolean $returnOnlyAttributes 是否仅返回属性合集
     * @return array
     */
    public function readAll($condition = null, $extra = null, $returnOnlyAttributes = false) {
        $records = SCS::db($this->_connect)->findAll('SELECT * FROM '.
            SCS::config()->db[$this->_connect]['prefix'].$this->_table.
            ($condition ? ' WHERE '.$condition : '').($extra ? (' '.$extra) : ''));
        $data = array();
        foreach($records as $record) {
            $curd = new SCCurd($this->_table, $this->_connect);
            $curd->setAttributes($record);
            array_push($data, $returnOnlyAttributes ? $curd->attributes() : $curd);
        }
        return $data;
    }
    
    /**
     * 获取所有属性
     * @return stdClass
     */
    public function attributes() {
        return $this->_attributes;
    }
    
    /**
     * 获取字段值
     * @param string $field
     * @throws Exception
     */
    public function __get($field) {
        if(in_array($field, $this->_fields)) {
            return $this->_attributes->$field;
        } else {
            throw new Exception('表'.$this->_connect.'.'.$this->_table.'中没有名为'.$field.'的字段', E_USER_ERROR);
        }
    }
    
    /**
     * 设置字段值
     * @param string $field
     * @param mixed $value
     * @throws Exception
     */
    public function __set($field, $value) {
        if(in_array($field, $this->_fields)) {
            $this->_attributes->$field= $value;
        } else {
            throw new Exception('表'.$this->_connect.'.'.$this->_table.'中没有名为'.$field.'的字段', E_USER_ERROR);
        }
    }
    
    public function __toString() {
        return json_encode($this->_attributes);    
    }
    
    private function setAttributes(stdClass $attributes) {
        $this->_attributes = $attributes;
        $this->_pkValue = $this->_attributes->{$this->_pkName};
    }
}